#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>

pthread_mutex_t mutex;
pthread_cond_t cond;

typedef struct sNode {
    int val;
    struct sNode* next;
} Node;

typedef struct sQueue {
    Node *head;
    Node *tail;
} Queue;

Queue getQueue() {
    Queue q;
    q.head = NULL;
    q.tail = NULL;
    return q;
}

int checkNull(Queue *q) {
    if (q->head == NULL) {
        return 1;
    }
    return 0;
}

void queue_push(Queue *q, int val) {
    Node *node = (Node*)malloc(sizeof(Node));
    node->val = val;
    node->next = NULL;
    if (q->head == NULL) {
        q->head = node;
        q->tail = node;
    } else {
        node->next = q->head;
        q->head = node;
    }
}

int queue_pop(Queue *q) {
    Node *node = q->head;
    if (node == q->tail) {
        q->head = NULL;
        q->tail = NULL;
        return node->val;
    }
    while (node->next != q->tail) {
        node = node->next;
    }
    int val = q->tail->val;
    free(node->next);
    node->next = NULL;
    q->tail = node;
    return val;
}

void* producer(void* arg) {
    Queue *q = (Queue*)arg;
    while (1) {
        int num = rand() % 1000;
        pthread_mutex_lock(&mutex);
        queue_push(q, num);
        printf("Produce %d\n", num);
        pthread_mutex_unlock(&mutex);
        pthread_cond_broadcast(&cond);  // 唤醒所有消费者线程来抢锁
        sleep(rand() % 3);
    }
    return NULL;
}

void* consumer(void* arg) {
    Queue *q = (Queue*)arg;
    while (1) {
        pthread_mutex_lock(&mutex);
        while (checkNull(q)) {
            pthread_cond_wait(&cond, &mutex);   // 开锁并等待条件触发重新获取锁
        }
        int num = queue_pop(q);
        printf("Consume %d\n", num);

        pthread_mutex_unlock(&mutex);
        sleep(rand() % 3);
    }
    return NULL;
}


int main() {
    pthread_t tid[10];
    pthread_mutex_init(&mutex, NULL); 
    pthread_cond_init(&cond, NULL);
    Queue q = getQueue();

    for (int i = 0; i < 5; ++i) {
        pthread_create(&tid[i], NULL, producer, &q);
        pthread_create(&tid[i + 5], NULL, consumer, &q);
    }

    for (int i = 0; i < 10; i++) {
        pthread_join(tid[i], NULL);
    }
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
}

